#include<io.h>
#include<sched.h>
#include<types.h>
#include<page.h>
#include<stdio.h>
#include<system.h>
#include<syscall.h>
#include<processor.h>
#include<irq.h>
#include<fcntl.h>
#include<stat.h>

#define	KRNL_STACK_SIZE	4096

extern void	root_task();
extern void	setup_kernel();

TSS	tss;
System	system;

char	krnlStack[KRNL_STACK_SIZE];
char	int_stack[INT_STACK_SIZE] __attribute__ ((__aligned__(PAGE_SIZE)));

int KernelEntry()
{
	asm(	"movl $krnlStack,%%esp;"
		"addl %%eax,%%esp;"
		::"a"(KRNL_STACK_SIZE));

	setup_kernel();

	asm("	movl	$0x23,%%eax;		\
		movw	%%ax,%%ds;		\
		movw	%%ax,%%es;		\
		movw	%%ax,%%fs;		\
		movw	%%ax,%%gs;		\
		pushl	$0x23;			\
		pushl	%%ebx;			\
		pushl	$0x282;			\
		pushl	$0x1B;			\
		leal	root_task,%%eax;	\
		pushl	%%eax;			\
		iret;"::"b"(KRNLADDR));
	return 0;
}

#if 0
void root_task()
{
	pid_t pid;
	pid = fork();
	if(pid < 0)
	{
		printf("failed create child\n");
		while(1);
	}
	else if(pid == 0)
	{
		execv("/bin/sh", NULL);
		while(1);
	}
	else
	{
		while(1)
		{

		}
	}
}
#else
void root_task()
{
	pid_t pid;
/*
	int fd = open("/boot/grub/grub.conf", O_RDONLY);
	//int fd = open("/bin/hw", O_RDONLY);
	printf("FD: %d\n", fd);
	char	buf[1024];
	int	filesz, i;
	Stat	stat;
	fstat(fd, &stat);
	filesz = stat.st_size;
	printf("file size: %d bytes\n", filesz);
	read(fd, buf, filesz);
	for(i=0; i<filesz; i++)
		printf("%c", buf[i]);
	execv("/bin/hw", NULL);
	while(0)
	{
		printf("r");
		int d=100000; while(d--);
	}
*/


//#define	SHOW	

	pid = fork();
#ifdef	SHOW
	printf("PID: %d\n", pid);
#endif
	if(pid < 0)
	{
		printf("failed create child\n");
		while(1);
	}
	else if(pid == 0)
	{
		pid_t ccid;
		ccid = fork();

#ifdef	SHOW
		printf("CCID: %d\n", ccid);
#endif

		if(ccid < 0)
		{
			printf("child faild to create child\n");
			while(1);
		}
		else if(ccid == 0)
		{
			execv("/bin/sh", NULL);
			while(1)
			{
#ifdef	SHOW
				printf("a");
#endif
				delay(100);
			}
		}
		else
		{
			while(1)
			{
#ifdef	SHOW
				printf("b");
#endif
				delay(200);
			}
		}
	}
	else
	{
		pid_t pcid;
		pcid = fork();
	
#ifdef	SHOW
		printf("PCID: %d\n", pcid);
#endif
		if(pcid < 0)
		{
			printf("parent faild to create child\n");
			while(1);
		}
		else if(pcid == 0)
		{
			while(1)
			{
#ifdef	SHOW
				printf("c");
#endif
				delay(300);
			}
		}
		else
		{
			while(1)
			{
#if 0
				int k;
				extern	void	ParseKbdInput(int k);
				k = read_kbd();
				ParseKbdInput(k);
#else
#ifdef	SHOW
				printf("d");
#endif
				delay(400);
#endif
			}
		}
	}
}
#endif

#if 0
int KernelEntry()
{
	unsigned int memSize= 0;
	int i;
	asm(	"movl $krnlStack,%%esp;"
		"addl %%eax,%%esp;"
		::"a"(KRNL_STACK_SIZE));

	extern void SetupKernel();
	SetupKernel();

	//Change Stack...
	//add_task(test_taskA);
	//add_task(test_taskB);
	//add_task(test_taskA);

#if 0
	#define	S 223
	pPage test[S];
	for(i=0; i<S; i++)
	{
		pPage pd = alloc_pages(i%MAX_ORDER);
		test[i] = pd;
		if(pd != NULL)
		{
			printk("###:%d %d %d", i, pd->mapNR, test[i]->mapNR);
		}
		disp_free_area();
	}
	for(i=0; i<S; i++)
	{
		if(test[i] != NULL)
		{
			free_pages(test[i],i%MAX_ORDER);
			disp_free_area();
			printk("###:%d %d", i, test[i]->mapNR);
		}
		//int j=1000000;while(j--);
	}

	printk("test success\n");
	while(1);
#endif

#if 0
	while(1)
	{
		for(i=0; i<MAX_ORDER; i++)
		{
			pPage page = alloc_pages(i);
			disp_free_area();
			free_pages(page,i);
			disp_free_area();
		}
	}
#endif

#if 0
	while(1)
	{
		pPage page = alloc_pages(0);
		disp_free_area();
		//int j=1000000;while(j--);
	}
#endif

#if 0
	#define	S	3333
	#define	O	4
	pPage pages[S];
	for(i=0; i<S; i++)
	{
		pages[i] = alloc_pages(O);
		if(pages[i]->mapNR == 0)
			printk("<%d %08x>", i, pages[i]);
	}
	disp_free_area();
	printk("alloc_finished\n");
	for(i=0; i<S; i++)
		if(pages[i] != NULL)
			free_pages(pages[i], O);
	disp_free_area();
	printk("free_finished\n");
	pListHead pos,tmp;
	list_for_each_safe(pos, tmp, &freeArea[O].freeList)
	{
		printk("*%d* ", list_entry(pos, Page, list)->mapNR);
	}
	printk("\n");
#endif
	//asm("sti;");
	/* Jump To RING 3 
	asm("	movl	$0x23,%eax;	\
		movw	%ax,%ds;	\
		movw	%ax,%es;	\
		movw	%ax,%fs;	\
		movw	%ax,%gs;	\
		movl	%esp,%ebp;	\
		pushl	$0x23;		\
		pushl	%ebp;		\
		pushl	$0x282;		\
		pushl	$0x1B;		\
		leal	ring3,%eax;	\
		pushl	%eax;		\
		iret");

	while(1)
	{
		unsigned long l = (unsigned long)kmalloc(PAGE_SIZE);
		if(l>0xC7FF0000)
			while(1);
	}
	*/

	asm("	movl	$0x23,%%eax;	\
		movw	%%ax,%%ds;	\
		movw	%%ax,%%es;	\
		movw	%%ax,%%fs;	\
		movw	%%ax,%%gs;	\
		pushl	$0x23;		\
		pushl	%%ebx;		\
		pushl	$0x282;		\
		pushl	$0x1B;		\
		leal	ring3,%%eax;	\
		pushl	%%eax;		\
		iret;"::"b"(KRNLADDR-4));
	return 0;
}

void ring3()
{
#if 1
	pid_t pid;
	extern void	delay(unsigned int d);

	pid = fork();
	//while(1);
	printf("PID:%d\n", pid);

	u32 *p_pd  = (u32 *) current->cr3; // parent's page dir
	u32 *p_pt;
	p_pd = pa2va(p_pd);
	printf("init current cr3 : %08x\n", p_pd);
	printf("init p_pd[767]:%08x\n", p_pd[767]);
	p_pt = pa2va((p_pd[767] & 0xFFFFF000));
	printf("init p_pt[1023]:%08x\n", p_pt[1023]);
	//while(1);
	if(pid < 0)
	{
		printf("failed create child\n");
	}
	else if(pid == 0)
	{
/*
		while(1)
		{
		extern	void	ParseKbdInput();
			ParseKbdInput();
		//	asm("xchg %bx, %bx");
		//	asm("nop; nop; nop;");
		}
*/
		printf("child\n");
		while(1)
		{
			printf("c");
			delay(400);
		}
	}
	else
	{
/*
		while(1)
		{
			asm("xchg %bx, %bx");
			asm("int $0x20");
			//printf("p");
			//ParseKbdInput();
		}
*/
		printf("parent\n");
		while(1)
		{
			printf("p");
			delay(500);
		}
	}

#else
	extern	void	ParseKbdInput();
	extern	void	delay(unsigned int d);
	extern	unsigned char read_kbd();

	while(1)
	{
		unsigned int k,t;
		//printf("%x", read_kbd());
		//asm("xchg %bx,%bx");
		//printf("I");
		//delay(300);
		ParseKbdInput();
	}
#endif
}
#endif


